package com.sagframe.sagacity.sqltoy.plus.multi;

import com.sagframe.sagacity.sqltoy.plus.conditions.eumn.CompareEnum;
import com.sagframe.sagacity.sqltoy.plus.conditions.eumn.SqlKeyword;
import com.sagframe.sagacity.sqltoy.plus.multi.interfaces.StringCondition;

public class StringMultiStepWrapper {

    /**
     * 连接表
     * @param <Children>
     */
    public interface LambdaFrom<Children extends AbstractStringMultiWrapper<Children>> {

        /**
         * 连接来源表 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaMatchJoin<Children> from(Class<T> tClass);

        /**
         * 连接来源表 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaMatchJoin<Children> from(Class<T> tClass, String alisaName);
    }

    /**
     * 连接方式
     * @param <Children>
     */
    public interface LambdaMatchJoin<Children extends AbstractStringMultiWrapper<Children>> {

        /**
         * 左连接 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaOn<Children> leftJoin(Class<T> tClass);

        /**
         * 左连接 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaOn<Children> leftJoin(Class<T> tClass, String alisaName);

        /**
         * 右连接 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaOn<Children> rightJoin(Class<T> tClass);

        /**
         * 右连接 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaOn<Children> rightJoin(Class<T> tClass, String alisaName);

        /**
         * 内连接 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaOn<Children> innerJoin(Class<T> tClass);

        /**
         * 内连接 - 不设置别名将自动生成 首先字母消息 + 序号（按先后顺序）
         * @param tClass
         * @param <T>
         * @return
         */
        <T> StringMultiStepWrapper.LambdaOn<Children> innerJoin(Class<T> tClass, String alisaName);

        /**
         * 不连接直接查单表
         * @return
         */
        StringCondition<Children> where();
    }

    /**
     * 连接关键字
     * @param <Children>
     */
    public interface LambdaOn<Children extends AbstractStringMultiWrapper<Children>> {

        /**
         * on连接
         * @return
         */
        StringMultiStepWrapper.LambdaOnCompare<Children> on();
    }

    /**
     * 连接条件
     * @param <Children>
     */
    public interface LambdaOnCompare<Children extends AbstractStringMultiWrapper<Children>> extends StringMultiStepWrapper.LambdaMatchJoin<Children> {

        /**
         *
         * @param columnA - 关联字段A
         * @param columnB - 关联字段B
         * @return
         */
        StringMultiStepWrapper.LambdaOnCompare<Children> eq(String columnA, String columnB);
    }

    /**
     * 步骤构造建造器
     * @param <Children>
     */
    public static class MultiStepWrapperBuilder<Children extends AbstractStringMultiWrapper<Children>> extends AbstractMultiStepWrapper implements StringMultiStepWrapper.LambdaFrom<Children>, StringMultiStepWrapper.LambdaMatchJoin<Children>, StringMultiStepWrapper.LambdaOn<Children>, StringMultiStepWrapper.LambdaOnCompare<Children> {

        private Children wrapperChildren;

        public MultiStepWrapperBuilder(Children wrapperChildren, MultiContext context) {
            super(context);
            this.wrapperChildren = wrapperChildren;
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaMatchJoin<Children> from(Class<T> tClass) {
            return from(tClass, null);
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaMatchJoin<Children> from(Class<T> tClass, String alisaName) {
            context.addTableSqlAssembler(tClass);
            context.addEntityClass(tClass);
            context.putTableAlisaName(tClass, alisaName);
            context.setFromClass(tClass);
            return this;
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaOn<Children> leftJoin(Class<T> tClass) {
            return leftJoin(tClass, null);
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaOn<Children> leftJoin(Class<T> tClass, String alisaName) {
            setContextISqlSegment(SqlKeyword.LEFT_JOIN, tClass, alisaName);
            return this;
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaOn<Children> rightJoin(Class<T> tClass) {
            return rightJoin(tClass, null);
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaOn<Children> rightJoin(Class<T> tClass, String alisaName) {
            setContextISqlSegment(SqlKeyword.RIGHT_JOIN, tClass, alisaName);
            return this;
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaOn<Children> innerJoin(Class<T> tClass) {
            return innerJoin(tClass, null);
        }

        @Override
        public <T> StringMultiStepWrapper.LambdaOn<Children> innerJoin(Class<T> tClass, String alisaName) {
            setContextISqlSegment(SqlKeyword.INNER_JOIN, tClass, alisaName);
            return this;
        }

        @Override
        public StringCondition<Children> where() {
            return wrapperChildren;
        }

        @Override
        public StringMultiStepWrapper.LambdaOnCompare<Children> on() {
            context.addTableSqlAssembler(SqlKeyword.ON);
            return this;
        }

        @Override
        public StringMultiStepWrapper.LambdaOnCompare<Children> eq(String columnA, String  columnB) {
            context.addSqlAssembler(mappingStrategy -> context.addTableSqlSegment(() -> getCompareOnSql(mappingStrategy, CompareEnum.LINK_EQ_SQL, context.getFiledNature(columnA), context.getFiledNature(columnB))));
            return this;
        }
    }
}
